package com.rbac.admin.aspect;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rbac.admin.annotation.OperationLog;
import com.rbac.admin.entity.system.SysOperationLog;
import com.rbac.admin.service.system.SysOperationLogService;
import com.rbac.admin.utils.IpUtils;
import com.rbac.admin.utils.SecurityUtils;
import com.rbac.admin.utils.SnowflakeIdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 操作日志AOP切面
 * 
 * @author RBAC-Admin
 * @since 2024-01-01
 */
@Aspect
@Component
@Slf4j
public class OperationLogAspect {

    @Autowired
    private SysOperationLogService operationLogService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    /**
     * 环绕通知，记录操作日志
     */
    @Around("@annotation(operationLog)")
    public Object around(ProceedingJoinPoint point, OperationLog operationLog) throws Throwable {
        
        long startTime = System.currentTimeMillis();
        
        // 构建日志对象
        SysOperationLog logEntity = buildOperationLog(point, operationLog);
        
        try {
            // 执行目标方法
            Object result = point.proceed();
            
            // 记录成功日志
            logEntity.setOperationResult(1);
            logEntity.setExecutionTime(System.currentTimeMillis() - startTime);
            
            // 记录响应结果
            if (operationLog.recordResult() && result != null) {
                try {
                    String responseResult = objectMapper.writeValueAsString(result);
                    // 限制响应结果长度，避免数据过大
                    if (responseResult.length() > 2000) {
                        responseResult = responseResult.substring(0, 2000) + "...";
                    }
                    logEntity.setResponseResult(responseResult);
                } catch (Exception e) {
                    logEntity.setResponseResult("响应结果序列化失败");
                    log.warn("序列化响应结果失败: {}", e.getMessage());
                }
            }
            
            // 异步保存日志
            saveLogAsync(logEntity);
            
            return result;
            
        } catch (Exception e) {
            // 记录失败日志
            logEntity.setOperationResult(0);
            logEntity.setExecutionTime(System.currentTimeMillis() - startTime);
            logEntity.setErrorMsg(e.getMessage());
            
            // 异步保存日志
            saveLogAsync(logEntity);
            
            throw e;
        }
    }

    /**
     * 构建操作日志对象
     */
    private SysOperationLog buildOperationLog(ProceedingJoinPoint point, OperationLog operationLog) {
        SysOperationLog logEntity = new SysOperationLog();
        
        try {
            // 生成雪花ID
            long snowflakeId = snowflakeIdGenerator.nextId();
            logEntity.setId(snowflakeId);
            log.debug("Generated snowflake ID for operation log: {}", snowflakeId);
            
            // 获取当前用户信息
            String userId = SecurityUtils.getCurrentUserId();
            String username = SecurityUtils.getCurrentUsername();
            String realName = SecurityUtils.getCurrentUserRealName();
            String roleId = SecurityUtils.getCurrentUserRoleId();
            String roleName = SecurityUtils.getCurrentUserRoleName();
            
            logEntity.setUserId(userId);
            logEntity.setUsername(username);
            logEntity.setRealName(realName);
            logEntity.setRoleId(roleId);
            logEntity.setRoleName(roleName);
            
            // 操作信息
            logEntity.setOperationModule(operationLog.module());
            logEntity.setOperationType(operationLog.type());
            logEntity.setOperationDesc(operationLog.value());
            logEntity.setOperationTime(LocalDateTime.now());
            
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                
                // 客户端信息
                logEntity.setIpAddress(IpUtils.getClientIp(request));
                logEntity.setUserAgent(request.getHeader("User-Agent"));
                
                // 请求参数
                if (operationLog.recordParams()) {
                    Object[] args = point.getArgs();
                    if (args != null && args.length > 0) {
                        try {
                            String params = objectMapper.writeValueAsString(args);
                            // 限制参数长度，避免数据过大
                            if (params.length() > 2000) {
                                params = params.substring(0, 2000) + "...";
                            }
                            logEntity.setRequestParams(params);
                        } catch (JsonProcessingException e) {
                            logEntity.setRequestParams("参数序列化失败");
                            log.warn("序列化请求参数失败: {}", e.getMessage());
                        }
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("构建操作日志失败: {}", e.getMessage(), e);
            // 设置默认值，确保日志能够保存
            if (logEntity.getId() == null) {
                logEntity.setId(snowflakeIdGenerator.nextId());
            }
            logEntity.setUserId("system");
            logEntity.setUsername("system");
            logEntity.setRealName("系统");
        }
        
        return logEntity;
    }

    /**
     * 异步保存日志
     */
    @Async("logTaskExecutor")
    public void saveLogAsync(SysOperationLog logEntity) {
        try {
            operationLogService.save(logEntity);
            log.debug("Operation log saved successfully with ID: {}", logEntity.getId());
        } catch (Exception e) {
            log.error("保存操作日志失败: {}", e.getMessage(), e);
        }
    }
}